package cn.itcast.hiss.form.service.impl;

import cn.hutool.core.util.StrUtil;
import cn.itcast.hiss.api.client.HissFormConstants;
import cn.itcast.hiss.api.client.dto.FormServerDefinitionDTO;
import cn.itcast.hiss.api.client.form.CreateFormDefinition;
import cn.itcast.hiss.api.client.form.FormDefinition;
import cn.itcast.hiss.api.client.form.FormSubmitData;
import cn.itcast.hiss.api.client.form.GetFormDefinition;
import cn.itcast.hiss.common.enums.StatutsType;
import cn.itcast.hiss.form.dto.FormDataDTO;
import cn.itcast.hiss.form.dto.FormDataInfoDTO;
import cn.itcast.hiss.form.dto.FormDetailDTO;
import cn.itcast.hiss.form.mapper.*;
import cn.itcast.hiss.form.mapper.drive.DatabaseDriver;
import cn.itcast.hiss.form.pojo.HissFormBytearray;
import cn.itcast.hiss.form.pojo.HissFormModel;
import cn.itcast.hiss.form.pojo.HissFormTableFields;
import cn.itcast.hiss.form.pojo.HissFormTables;
import cn.itcast.hiss.form.service.DynamicTableService;
import cn.itcast.hiss.form.service.HissFormModelService;
import cn.itcast.hiss.message.MessageContext;
import cn.itcast.hiss.message.sender.form.CreateFormDefinitionMessage;
import cn.itcast.hiss.message.sender.form.FormSubmitDataMessage;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/*
 * @author miukoo
 * @description 对表单进行增删改查
 * @date 2023/6/26 14:40
 * @version 1.0
 **/
@Service
@Transactional
@Slf4j
public class HissFormModelServiceImpl implements HissFormModelService {

    @Autowired
    private HissFormModelMapper hissFormModelMapper;
    @Autowired
    private HissFormBytearrayMapper hissFormBytearrayMapper;
    @Autowired
    private HissFormTablesMapper hissFormTablesMapper;
    @Autowired
    private HissFormTableFieldsMapper hissFormTableFieldsMapper;
    @Autowired
    private DatabaseDriver databaseDriver;
    @Autowired
    private HissDynamicTableMapper hissDynamicTableMapper;
    @Autowired
    private DynamicTableService dynamicTableService;

    /**
     * 查找字段标识
     * @param hissFormTables
     * @param key
     * @return
     */
    public HissFormTableFields findHissFormTableFields(List<HissFormTableFields> hissFormTables, String key ){
        for (HissFormTableFields hissFormTable : hissFormTables) {
            if(key.equals(hissFormTable.getControlId())){
                return hissFormTable;
            }
        }
        return null;
    }


    @Override
    public void deleteByModelId(String modelId) {
        hissFormModelMapper.deleteById(modelId);
        hissFormBytearrayMapper.deleteByDataId(modelId);

        // 删除表
        List<HissFormTables> hissFormTables = hissFormTablesMapper.listByModelId(modelId);
        hissFormTablesMapper.deleteByModelId(modelId);

        // 删除字段信息
        hissFormTableFieldsMapper.deleteByModelId(modelId);

        // 删除物理表
        if(hissFormTables!=null){
            for (HissFormTables hissFormTable : hissFormTables) {
                String sql = String.format("drop table `%s`",hissFormTable.getTablePhysicalName());
                databaseDriver.executeSql(sql);
            }
        }
    }

    /**
     * 新增或修改表单——新增
     * @param message
     * @param messageContext
     */
    @Override
    public void saveFormDefinition(CreateFormDefinitionMessage message, MessageContext messageContext) {
        CreateFormDefinition palyload = message.getPalyload();
        String id = palyload.getId();
        String tenantId = palyload.getUserAppId();
        if(StrUtil.isEmpty(tenantId)){
            tenantId = message.getMessageAuth().getTenant();
        }
        if(StrUtil.isNotEmpty(id)){
            // 修改
            doUpdateAction(id,palyload,messageContext,tenantId);
        }else{
            // 新增
            doAddAction(palyload,messageContext,tenantId);
        }
    }

    /**
     * 修改
     * @param id
     * @param palyload
     * @param messageContext
     * @param tenantId
     */
    public void doUpdateAction(String id, CreateFormDefinition palyload, MessageContext messageContext, String tenantId) {
        HissFormModel hissFormModel = hissFormModelMapper.selectById(id);
        if(hissFormModel==null){
            messageContext.addError("msg","无效参数");
            return;
        }
        if (!hissFormModel.getTenantId().equals(tenantId)){
            messageContext.addError("msg","无权限操作");
            return;
        }
        String formDetail = palyload.getFormDetail();
        FormDetailDTO formDetailDTO = JSON.parseObject(formDetail, FormDetailDTO.class);
        // 修改基本信息
        updateHissFormModel(palyload,hissFormModel,formDetailDTO);
        // 修改JSON
        updateHissFormArray(hissFormModel,formDetail);
        // 修改表信息
        HissFormTables table = updateTable(hissFormModel);
        // 修改字段：新增字段、修改字段、删除字段
        updateFiled(hissFormModel,table,formDetailDTO);
        messageContext.addResultAndCount("msg","保存成功");
    }

    /**
     * 修改字段信息
     * @param hissFormModel
     * @param table
     * @param formDetailDTO
     */
    public void updateFiled(HissFormModel hissFormModel,HissFormTables table,FormDetailDTO formDetailDTO){
        List<HissFormTableFields> fields = hissFormTableFieldsMapper.listByModelId(hissFormModel.getId());
        Map<String, HissFormTableFields> map = fields.stream().collect(Collectors.toMap(HissFormTableFields::getControlId, Function.identity()));// 当前数据库中已经存在的字段
//        Map<字段id,字段信息> map = new Map<字段id, 字段信息>();// 当前数据库中已经存在的字段
        // 获取前端字段的id，判断其是否在map集合中？如果在为修改，如果不在则为新增
        List<FormDataInfoDTO> data = formDetailDTO.getFormData().get(0).getData();
        List<HissFormTableFields> fileds =  new ArrayList<>();
        for (FormDataInfoDTO field : data) {
            if(map.containsKey(field.getId())){
                // 修改
                HissFormTableFields hissFormTableFields = map.get(field.getId());
                updateHissFormTableFields(hissFormTableFields,field);
            }else{
                // 新增：插入HissFormTableFields并创建物理字段
                HissFormTableFields hissFormTableFields = createField(hissFormModel, table, field);
                fileds.add(hissFormTableFields);
                // 创建物理字段
//                hissDynamicTableMapper.createField(table,hissFormTableFields);
            }
        }
        //  Map<字段Id,字段信息> temp // 前端传入的字段集合
        // 判断后端数据库存在的字段是否在前端字段集合中，如果不在则为删除
        Map<String, FormDataInfoDTO> temp = data.stream().collect(Collectors.toMap(FormDataInfoDTO::getId, Function.identity()));
        for (String key : map.keySet()) {
            if(!temp.containsKey(key)){
                // 删除
                HissFormTableFields hissFormTableFields = map.get(key);
                hissFormTableFields.setStatus(StatutsType.DISABLE.getCode());
                hissFormTableFieldsMapper.updateById(hissFormTableFields);
            }
        }
        // 创建物理的字段
        dynamicTableService.createPhysicalField(table,fileds);
    }

    /**
     * 修改字段信息
     * @param hissFormTableField
     * @param field
     */
    private void updateHissFormTableFields(HissFormTableFields hissFormTableField, FormDataInfoDTO field) {
        hissFormTableField.setSearchDisplay(field.getData().getSearchDisplay());
        hissFormTableField.setFieldName(field.getData().getTitle());
        hissFormTableField.setFieldType(field.getType());
        hissFormTableField.setListDisplay(field.getData().getListDisplay());
        hissFormTableField.setSearchType(field.getData().getSearchType());
        hissFormTableField.setIsOnly(field.getData().getIsOnly());
        hissFormTableFieldsMapper.updateById(hissFormTableField);
    }

    public HissFormTables updateTable(HissFormModel hissFormModel){
        HissFormTables hissFormTables = hissFormTablesMapper.selectMainTable(hissFormModel.getId());
        hissFormTables.setTableName(hissFormModel.getName());
        hissFormTablesMapper.updateById(hissFormTables);
        return hissFormTables;
    }

    /**
     * 修改JSON
     * @param hissFormModel
     * @param json
     */
    private void updateHissFormArray(HissFormModel hissFormModel, String json) {
        HissFormBytearray modelJson = hissFormBytearrayMapper.getModelJson(hissFormModel.getId(), HissFormConstants.FORM_CONFIG_JSON);
        modelJson.setContent(json);
        modelJson.setRev(modelJson.getRev()+1);
        hissFormBytearrayMapper.updateById(modelJson);
    }

    /**
     * 修改基本信息
     * @param palyload
     * @param hissFormModel
     * @param formDetailDTO
     */
    private void updateHissFormModel(CreateFormDefinition palyload, HissFormModel hissFormModel,FormDetailDTO formDetailDTO){
        hissFormModel.setName(formDetailDTO.getBaseFormData().getFormTitle());
        hissFormModel.setIcon(formDetailDTO.getBaseFormData().getIcon());
        hissFormModel.setCategory(formDetailDTO.getBaseFormData().getGroupId());
        hissFormModel.setDescription(formDetailDTO.getBaseFormData().getFormDescribe());
        hissFormModelMapper.updateById(hissFormModel);
    }

    /**
     * 新增
     * @param palyload
     * @param messageContext
     * @param tenantId
     */
    private void doAddAction(CreateFormDefinition palyload, MessageContext messageContext, String tenantId) {
        String formDetail = palyload.getFormDetail();
        FormDetailDTO formDetailDTO = JSON.parseObject(formDetail, FormDetailDTO.class);
        // 保存基本信息
        HissFormModel hissFormModel = createHissFormModel(formDetailDTO, messageContext, tenantId);
        // 保存json信息
        createHissFormBytearray(hissFormModel.getId(),palyload.getFormDetail());
        // 创建物理表的映射数据
        HissFormTables table = createTable(hissFormModel);
        // 创建物理表
        //hissDynamicTableMapper.createTable(hissFormModel,table);
        // 创建物理表映射的字段数据
        List<FormDataDTO> formData = formDetailDTO.getFormData();
        FormDataDTO formDataDTO = formData.get(0);
        List<FormDataInfoDTO> data = formDataDTO.getData();
        List<HissFormTableFields> fileds =  new ArrayList<>();
        for (FormDataInfoDTO field : data) {
            HissFormTableFields hissFormTableFields = createField(hissFormModel, table, field);
            fileds.add(hissFormTableFields);
            // 创建物理字段
//            hissDynamicTableMapper.createField(table,hissFormTableFields);
        }
        // 使用另外一个事务来创建物理表和物理字段
        dynamicTableService.createPhysicalTable(hissFormModel,table,fileds);
        messageContext.addResultAndCount("msg","保存成功");
    }

    /**
     * 创建一个字段的映射信息
     * @param hissFormModel
     * @param table
     * @param field
     */
    public HissFormTableFields createField(HissFormModel hissFormModel,HissFormTables table,FormDataInfoDTO field){
        HissFormTableFields hissFormTableField = new HissFormTableFields();
        hissFormTableField.setStatus(StatutsType.ENABLE.getCode());
        hissFormTableField.setModelId(hissFormModel.getId());
        hissFormTableField.setSearchDisplay(field.getData().getSearchDisplay());
        hissFormTableField.setLevel(0);// 当前字段数据第几层表的字段
        hissFormTableField.setFieldName(field.getData().getTitle());
        hissFormTableField.setFieldType(field.getType());
        hissFormTableField.setTableId(table.getId());
        hissFormTableField.setCreatedTime(new Date());
        hissFormTableField.setListDisplay(field.getData().getListDisplay());
        hissFormTableField.setSearchType(field.getData().getSearchType());
        hissFormTableField.setControlId(field.getId());
        hissFormTableField.setIsOnly(field.getData().getIsOnly());
        hissFormTableField.setPhysicalName("hf_"+field.getId());// 表中物理名称
        hissFormTableFieldsMapper.insert(hissFormTableField);
        return hissFormTableField;
    }

    /**
     * 创建物理表的映射数据
     * @param hissFormModel
     */
    public HissFormTables createTable(HissFormModel hissFormModel){
        HissFormTables hissFormTables = new HissFormTables();
        hissFormTables.setTablePhysicalName("hf_"+System.currentTimeMillis());
        hissFormTables.setTableName(hissFormModel.getName());
        hissFormTables.setModelId(hissFormModel.getId());
        hissFormTables.setCreatedTime(new Date());
        hissFormTables.setStatus(StatutsType.ENABLE.getCode());
        hissFormTables.setFlag("main");
        hissFormTablesMapper.insert(hissFormTables);
        return hissFormTables;
    }

    public void createHissFormBytearray(String dataId, String json){
        HissFormBytearray hissFormBytearray = new HissFormBytearray();
        hissFormBytearray.setContent(json);
        hissFormBytearray.setRev(1);
        hissFormBytearray.setDataId(dataId);
        hissFormBytearray.setName(HissFormConstants.FORM_CONFIG_JSON);
        hissFormBytearrayMapper.insert(hissFormBytearray);
    }

    /**
     * 保存基本信息
     * @param formDetailDTO
     * @param messageContext
     * @param tenantId
     */
    public HissFormModel createHissFormModel(FormDetailDTO formDetailDTO,MessageContext messageContext, String tenantId){
        HissFormModel hissFormModel = new HissFormModel();
        hissFormModel.setStatus(StatutsType.ENABLE.getCode());
        hissFormModel.setTenantId(tenantId);
        hissFormModel.setIcon(formDetailDTO.getBaseFormData().getIcon());
        hissFormModel.setName(formDetailDTO.getBaseFormData().getFormTitle());
        hissFormModel.setCategory(formDetailDTO.getBaseFormData().getGroupId());
        hissFormModel.setDescription(formDetailDTO.getBaseFormData().getFormDescribe());
        hissFormModel.setVersion("1.0.0");
        hissFormModel.setCreatedTime(new Date());
        hissFormModelMapper.insert(hissFormModel);
        return hissFormModel;
    }

    /**
     * 查询表单数据
     * @param formDefinition
     * @param messageContext
     * @return
     */
    @Override
    public List<FormServerDefinitionDTO>  queryFormInfo(GetFormDefinition formDefinition, MessageContext messageContext) {
        List<HissFormModel> hissFormModels = queryByGetFormDefinition(formDefinition);
        if(hissFormModels!=null){
            return hissFormModels.stream().map(model -> {
                FormServerDefinitionDTO definition = new FormServerDefinitionDTO();
                definition.setId(model.getId());
                definition.setName(model.getName());
                definition.setFields(hissFormTableFieldsMapper.listByModelIdForProcessConfig(model.getId()));
                return definition;
            }).collect(Collectors.toList());
        }else{
            return   new ArrayList<>();
        }
    }

    /**
     * 查询表单
     * @param formDefinition
     * @return
     */
    private List<HissFormModel> queryByGetFormDefinition(GetFormDefinition formDefinition){
        LambdaQueryWrapper<HissFormModel> wrapper = Wrappers.lambdaQuery();
        int count = 0;
        if(formDefinition!=null){
            if(StrUtil.isNotEmpty(formDefinition.getIds())){
                count++;
                wrapper.in(HissFormModel::getId,formDefinition.getIds());
            }
            if(StrUtil.isNotEmpty(formDefinition.getQuery())){
                count++;
                wrapper.like(HissFormModel::getName,formDefinition.getQuery());
            }
        }
        if(StrUtil.isNotEmpty(formDefinition.getTenantId())) {
            wrapper.eq(HissFormModel::getTenantId, formDefinition.getTenantId());
        }
        wrapper.orderByDesc(HissFormModel::getCreatedTime);
        Page<HissFormModel> page = Page.of(0,10);// 设置最多10条
        page = hissFormModelMapper.selectPage(page, count>0?wrapper:null);
        return page.getRecords();
    }

    @Override
    public void queryForm(GetFormDefinition formDefinition, MessageContext messageContext) {
        List<HissFormModel> hissFormModels = queryByGetFormDefinition(formDefinition);
        if(hissFormModels!=null){
            List<FormDefinition> definitions = hissFormModels.stream().map(model -> {
                FormDefinition definition = new FormDefinition();
                definition.setId(model.getId());
                definition.setName(model.getName());
                HissFormBytearray modelJson = hissFormBytearrayMapper.getModelJson(model.getId(), HissFormConstants.FORM_CONFIG_JSON);
                if (modelJson != null) {
                    definition.setContext(modelJson.getContent());
                }
                return definition;
            }).collect(Collectors.toList());
            messageContext.addResultAndCount("res",definitions);
        }else{
            hissFormModels =  new ArrayList<>();
            messageContext.addResultAndCount("res",hissFormModels);
        }
    }


    /**
     * 保存数据
     * @param params
     * @param messageContext
     * @throws Exception
     */
    @Override
    public void submitFormData(FormSubmitDataMessage params, MessageContext messageContext) throws Exception {
        // 保存新增还是修改
        FormSubmitData palyload = params.getPalyload();
        String dataId = palyload.getDataId();
        String userId = params.getMessageAuth().getCurrentUser().getUserId();
        String formId = palyload.getFormId();
        HissFormTables table = hissFormTablesMapper.selectMainTable(formId);
        if(StrUtil.isEmpty(dataId)){
            // 修改：update 表名 set 字段1=值,字段2=值 where id=dataId;
            // 新增：方式一：insert into 表名 (字段1,字段2) values (值1，值2);
            // 保存数据到物理表
            // 新增方式二： insert into 表名 （默认字段） values (值1，值2)  插入一条数据，数据值有默认字段的值【选用】
            dataId = UUID.randomUUID().toString();
            hissDynamicTableMapper.createData(table,dataId,userId);
        }
        updateInfo(palyload,table,dataId);
        messageContext.addResultAndCount("result",dataId);
    }

    @Override
    public void queryFormData(FormSubmitDataMessage params, MessageContext messageContext) {
        FormSubmitData palyload = params.getPalyload();
        HissFormModel hissFormModel = hissFormModelMapper.selectById(palyload.getFormId());
        if(hissFormModel!=null){
            HissFormTables mainTable = hissFormTablesMapper.selectMainTable(palyload.getFormId());
            if(mainTable!=null){
                Map<String, Object> data = hissDynamicTableMapper.getData(mainTable, palyload.getDataId());
                if( data==null ){ // 如果没有数据则进行自动填充
                    data = new HashMap();
                }
                // 把hf_开头的字段，修改该成控件开头的
                Map<String, Object> map = new HashMap<>();
                data.forEach((key,val)->{
                    if(val instanceof LocalDateTime){
                        LocalDateTime date = (LocalDateTime)val;
                        val = date.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
                    }
                    if(key.startsWith("hf_")){
                        map.put(key.replaceFirst("hf_",""),val);
                    }else{
                        map.put(key,val);
                    }
                });
                messageContext.addResultAndCount("result",map);
            }else{
                messageContext.addError("msg","未找到对应的表单存储表信息");
            }
        }else{
            messageContext.addError("msg","未找到对应的表单");
        }
    }

    private void updateInfo(FormSubmitData palyload,HissFormTables table,String dataId){
        // 把表单字段的值更新到上对应行中，update 表名  set 字段名=值 where id=dataId；
        Map<String, Object> data = palyload.getFormData().get(0).getData();
        // 默认字段不允许更新
        data.remove("id");
        data.remove("created_time");
        data.remove("user_id");
        data.remove("form_id");
        data.remove("table_id");
        hissDynamicTableMapper.updateData(table,dataId,data);
    }
}
